import os
import subprocess
import getpass
import shlex
import tempfile

__all__ = ['FileSys']

from time import sleep


class Cloud:
    def __init__(self):
        self.username = 'pytest'
        self.private_key_file = '.ssh/id_rsa'
        # self.passwd = 'python-project'
        self.server_ip = '8.141.10.41'
        self.timeout_seconds = 5
        self.modify_permission(self.private_key_file)

    def modify_permission(self, file_path: str):
        """
        otherwise, the ssh command will fail to log in without password,
        the error message is
        "Permissions for '.ssh/id_rsa' are too open.
        It is required that your private key files are NOT accessible by others.
        This private key will be ignored.
        Load key ".ssh/id_rsa": bad permissions"
        """
        username = getpass.getuser()
        cmd = f'icacls {file_path} /inheritance:r ; icacls {file_path} /remove Everyone ; icacls {file_path} /grant {username}:R'
        subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

    def exec_one_instruction(self, instruction: str) -> str:
        """
        Execute one instruction on the server
        :param instruction: the instruction to be executed
        :return: the result of the instruction
        """
        cmd = f'ssh -i {self.private_key_file} {self.username}@{self.server_ip} "{instruction}"'
        # print(cmd)
        result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                timeout=self.timeout_seconds)
        if result.returncode != 0:
            raise Exception(result.stderr.decode())
        return result.stdout.decode().strip()

    def upload_file(self, name, content, server_dir):
        """
        Upload a file to the server
        :param name: the name of the file
        :param content: the content of the file
        :param server_dir: the directory to save the file
        """
        tmp_file = os.path.join(tempfile.gettempdir(), name)
        with open(tmp_file, 'w') as f:
            f.write(content)
        cmd = f'scp -i {self.private_key_file} {tmp_file} {self.username}@{self.server_ip}:{server_dir}'
        # print(cmd)
        result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                timeout=self.timeout_seconds)
        os.remove(tmp_file)
        if result.returncode != 0:
            raise Exception(result.stderr.decode())

class FileSys:
    def __init__(self):
        self.cloud = Cloud()
        # The directory saving files
        self.local_dir = 'data/files'
        self.server_dir = '/home/pytest/py-project'
        if not os.path.exists(self.local_dir):
            os.mkdir(self.local_dir)

    def save_file(self, name: str, content: str):
        """
        Save a file
        :param name: the name of the file
        :param content: the content of the file
        """
        self.cloud.upload_file(name, content, self.server_dir)

    def get_file(self, name) -> str:
        """
        Get the content of a file
        :param name:  the name of the file
        :return:  the content of the file
        """
        cmd = f'cat {self.server_dir}/{name}'
        content = self.cloud.exec_one_instruction(cmd)
        return content

    def delete_file(self, name):
        """
        Delete a file
        :param name:  the name of the file
        :return:  True if the file is deleted successfully, False otherwise
        """
        cmd = f'rm -f {self.server_dir}/{name}'
        self.cloud.exec_one_instruction(cmd)

    def get_file_list(self) -> [str]:
        """
        Get the name of files
        :return:  the name of files
        """
        cmd = f'ls {self.server_dir}'
        result = self.cloud.exec_one_instruction(cmd)
        return result.split()

    def rename_file(self, old_name, new_name):
        """
        Rename a file
        :param old_name:
        :param new_name:
        """
        cmd = f'mv {self.server_dir}/{old_name} {self.server_dir}/{new_name}'
        self.cloud.exec_one_instruction(cmd)


if __name__ == '__main__':
    fs = FileSys()
    fs.save_file('test.txt', 'hello "<>~`!?"\'\\/.,world')
    # fs.save_file('test2.txt', 'hello world 2')
    # print(fs.get_file('test.txt'))
    # print(fs.get_file_list())
    # fs.rename_file('test.txt', 'test3.txt')
    # fs.delete_file('test3.txt')
    # print(fs.get_file_list())
